@scrider/formatter 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Schema, conversion and block handlers for rich-text content. HTML, Markdown, san
8
8
 
9
9
  ## Key Features
10
10
 
11
- - **Schema** — extensible format registry (31 built-in formats: inline, block, embed)
11
+ - **Schema** — extensible format registry (32 built-in formats: inline, block, embed — including `softBreak` for Shift+Enter line breaks)
12
12
  - **HTML conversion** — `deltaToHtml()` / `htmlToDelta()` with DOM adapters (browser + Node.js)
13
13
  - **Markdown conversion** — `deltaToMarkdown()` / `markdownToDelta()` (GFM, math, footnotes)
14
14
  - **Block handlers** — tables, footnotes, alerts, columns, inline-box
@@ -65,7 +65,7 @@ const delta = htmlToDelta(html, { registry });
65
65
  ```typescript
66
66
  import { Registry, createDefaultRegistry, BlockHandlerRegistry } from '@scrider/formatter';
67
67
 
68
- const registry = createDefaultRegistry(); // 31 built-in formats
68
+ const registry = createDefaultRegistry(); // 32 built-in formats
69
69
  ```
70
70
 
71
71
  ### HTML Conversion
@@ -86,6 +86,35 @@ deltaToMarkdown(delta, options?) // Delta → Markdown string
86
86
  await markdownToDelta(markdown, options?) // Markdown string → Delta (async)
87
87
  ```
88
88
 
89
+ ### Soft Line Break (`softBreak` embed)
90
+
91
+ A `Shift+Enter` style line break that does **not** split the containing block. Stored in Delta as `{ insert: { softBreak: true } }` and round-tripped consistently across all three layers:
92
+
93
+ | Direction | Encoding |
94
+ |-----------|----------|
95
+ | HTML | `<br data-scrider-embed>` (the marker disambiguates it from the `<br>` placeholder inside an empty paragraph) |
96
+ | Markdown | `" \n"` by default — GFM hard break; switch to inline `<br>` via `deltaToMarkdown(delta, { softBreakStyle: 'html' })` |
97
+
98
+ `htmlToDelta` also recognises bare `<br>` between content (e.g. `<p>foo<br>bar</p>`) as a soft break, while keeping the leading / placeholder shapes (`<p><br></p>`, `<p><br>foo</p>`) as regular newlines for backward compatibility.
99
+
100
+ ```typescript
101
+ import { Delta, deltaToHtml, deltaToMarkdown } from '@scrider/formatter';
102
+
103
+ const doc = new Delta()
104
+ .insert('hello')
105
+ .insert({ softBreak: true })
106
+ .insert('world\n');
107
+
108
+ deltaToHtml(doc);
109
+ // → '<p>hello<br data-scrider-embed>world</p>'
110
+
111
+ deltaToMarkdown(doc);
112
+ // → 'hello \nworld'
113
+
114
+ deltaToMarkdown(doc, { softBreakStyle: 'html' });
115
+ // → 'hello<br>world'
116
+ ```
117
+
89
118
  ### Sanitization
90
119
 
91
120
  ```typescript
package/dist/index.cjs CHANGED
@@ -63,6 +63,7 @@ __export(index_exports, {
63
63
  dividerFormat: () => dividerFormat,
64
64
  escapeHtml: () => escapeHtml,
65
65
  extractBoxOpAttributes: () => extractBoxOpAttributes,
66
+ extractTableRegion: () => extractTableRegion,
66
67
  fontFormat: () => fontFormat,
67
68
  footnoteRefFormat: () => footnoteRefFormat,
68
69
  footnotesBlockHandler: () => footnotesBlockHandler,
@@ -77,6 +78,7 @@ __export(index_exports, {
77
78
  isAdapterAvailable: () => isAdapterAvailable,
78
79
  isElement: () => isElement,
79
80
  isRemarkAvailable: () => isRemarkAvailable,
81
+ isTableNewlineOp: () => isTableNewlineOp,
80
82
  isTextNode: () => isTextNode,
81
83
  isValidColor: () => isValidColor,
82
84
  isValidHexColor: () => isValidHexColor,
@@ -89,10 +91,12 @@ __export(index_exports, {
89
91
  markdownToDeltaSync: () => markdownToDeltaSync,
90
92
  nodeAdapter: () => nodeAdapter,
91
93
  normalizeDelta: () => normalizeDelta,
94
+ preloadRemark: () => preloadRemark,
92
95
  sanitizeDelta: () => sanitizeDelta,
93
96
  sizeFormat: () => sizeFormat,
94
97
  slugify: () => slugify,
95
98
  slugifyWithDedup: () => slugifyWithDedup,
99
+ softBreakFormat: () => softBreakFormat,
96
100
  strikeFormat: () => strikeFormat,
97
101
  subscriptFormat: () => subscriptFormat,
98
102
  superscriptFormat: () => superscriptFormat,
@@ -2017,7 +2021,13 @@ var EMBED_RENDERERS = {
2017
2021
  const id = typeof value === "string" ? value : String(value);
2018
2022
  return `<sup class="footnote-ref"><a href="#fn-${escapeHtml(id)}" id="fnref-${escapeHtml(id)}">[${escapeHtml(id)}]</a></sup>`;
2019
2023
  },
2020
- divider: () => "<hr>"
2024
+ divider: () => "<hr>",
2025
+ // Soft line break (Shift+Enter equivalent). Emitted with an explicit
2026
+ // `data-scrider-embed` marker so that html-to-delta can distinguish this
2027
+ // embed from the placeholder `<br>` that appears inside an empty
2028
+ // paragraph (`<p><br></p>`) without relying solely on positional
2029
+ // heuristics. See `soft-break.ts` for the format definition.
2030
+ softBreak: () => "<br data-scrider-embed>"
2021
2031
  };
2022
2032
  var TAG_TO_INLINE_FORMAT = {
2023
2033
  strong: { format: "bold", value: true },
@@ -2255,6 +2265,33 @@ var imageFormat = {
2255
2265
  }
2256
2266
  };
2257
2267
 
2268
+ // src/schema/formats/embed/soft-break.ts
2269
+ var softBreakFormat = {
2270
+ name: "softBreak",
2271
+ scope: "embed",
2272
+ normalize(value) {
2273
+ return !!value;
2274
+ },
2275
+ validate(value) {
2276
+ return value === true;
2277
+ },
2278
+ render() {
2279
+ return "<br data-scrider-embed>";
2280
+ },
2281
+ match(element) {
2282
+ if (element.tagName.toLowerCase() !== "br") return null;
2283
+ if (!element.hasAttribute("data-scrider-embed")) return null;
2284
+ return { value: true };
2285
+ }
2286
+ // NB: Markdown rendering is intentionally NOT implemented on the format
2287
+ // itself. The choice between `" \n"` (GFM spaces) and inline `<br>`
2288
+ // depends on the caller-provided `softBreakStyle` option on
2289
+ // `deltaToMarkdown`, so the converter handles it as a built-in special
2290
+ // case instead of going through `Format.toMarkdown`. The Markdown side
2291
+ // of the round-trip is symmetric: `markdownToDelta` recognises both
2292
+ // `break` AST nodes and inline `<br>` HTML and emits this embed.
2293
+ };
2294
+
2258
2295
  // src/schema/formats/embed/video.ts
2259
2296
  var videoFormat = {
2260
2297
  name: "video",
@@ -2357,6 +2394,7 @@ var defaultEmbedFormats = [
2357
2394
  videoFormat,
2358
2395
  formulaFormat,
2359
2396
  dividerFormat,
2397
+ softBreakFormat,
2360
2398
  blockFormat,
2361
2399
  footnoteRefFormat
2362
2400
  ];
@@ -3187,7 +3225,12 @@ function htmlToDelta(html, options = {}) {
3187
3225
  return;
3188
3226
  }
3189
3227
  if (tagName === "br") {
3190
- context.pushNewline();
3228
+ const hasMarker = node.hasAttribute("data-scrider-embed");
3229
+ if (hasMarker || hasMeaningfulPrevSibling(node)) {
3230
+ context.pushEmbed({ softBreak: true });
3231
+ } else {
3232
+ context.pushNewline();
3233
+ }
3191
3234
  return;
3192
3235
  }
3193
3236
  processChildren(node);
@@ -3621,6 +3664,23 @@ function normalizeText(text, pendingText, atLineStart) {
3621
3664
  }
3622
3665
  return text;
3623
3666
  }
3667
+ function hasMeaningfulPrevSibling(brNode) {
3668
+ const parent = brNode.parentNode;
3669
+ if (!parent) return false;
3670
+ const children = parent.childNodes;
3671
+ for (let i = 0; i < children.length; i++) {
3672
+ const child = children[i];
3673
+ if (!child) continue;
3674
+ if (child === brNode) return false;
3675
+ if (child.nodeType === NODE_TYPE.TEXT_NODE) {
3676
+ const text = child.textContent ?? "";
3677
+ if (text.trim().length > 0) return true;
3678
+ } else if (isElement(child)) {
3679
+ return true;
3680
+ }
3681
+ }
3682
+ return false;
3683
+ }
3624
3684
  function findTagHandler(handlers, element, tagName) {
3625
3685
  const className = element.getAttribute("class");
3626
3686
  if (className) {
@@ -3756,7 +3816,9 @@ function deltaToMarkdown(delta, options = {}) {
3756
3816
  embedRenderers = {},
3757
3817
  blockHandlers,
3758
3818
  prettyHtml = false,
3759
- registry
3819
+ registry,
3820
+ softBreakStyle = "spaces",
3821
+ trimTrailingNewlines = false
3760
3822
  } = options;
3761
3823
  const useLatexDelimiters = mathSyntax === "latex";
3762
3824
  const lines = splitIntoLines2(delta.ops);
@@ -3772,7 +3834,9 @@ function deltaToMarkdown(delta, options = {}) {
3772
3834
  const isBlockquote = !!attrs.blockquote;
3773
3835
  if (typeof attrs["table-row"] === "number" && typeof attrs["table-col"] === "number") {
3774
3836
  const tableLines = collectTableLines2(lines, i);
3775
- result.push(renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters, registry));
3837
+ result.push(
3838
+ renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
3839
+ );
3776
3840
  result.push("");
3777
3841
  i += tableLines.length - 1;
3778
3842
  lastListType = null;
@@ -3788,7 +3852,16 @@ function deltaToMarkdown(delta, options = {}) {
3788
3852
  const codeLines = collectCodeBlock(lines, i);
3789
3853
  const language = getCodeBlockLanguage2(attrs);
3790
3854
  const code = codeLines.map(
3791
- (l) => renderLineContent2(l.ops, embedRenderers, true, false, blockHandlers, false, registry)
3855
+ (l) => renderLineContent2(
3856
+ l.ops,
3857
+ embedRenderers,
3858
+ true,
3859
+ false,
3860
+ blockHandlers,
3861
+ false,
3862
+ registry,
3863
+ softBreakStyle
3864
+ )
3792
3865
  ).join("\n");
3793
3866
  if (language === "math") {
3794
3867
  if (mathBlock === false) {
@@ -3838,7 +3911,8 @@ ${code}
3838
3911
  useLatexDelimiters,
3839
3912
  blockHandlers,
3840
3913
  prettyHtml,
3841
- registry
3914
+ registry,
3915
+ softBreakStyle
3842
3916
  );
3843
3917
  if (!content && !hasBlockFormat(attrs)) {
3844
3918
  result.push(preserveEmptyLines ? "<br>" : "");
@@ -3854,7 +3928,8 @@ ${code}
3854
3928
  lastIndent = indent;
3855
3929
  lastWasBlockquote = isBlockquote;
3856
3930
  }
3857
- return result.join("\n");
3931
+ const md = result.join("\n");
3932
+ return trimTrailingNewlines ? md.replace(/\n+$/, "") : md;
3858
3933
  }
3859
3934
  function hasBlockFormat(attrs) {
3860
3935
  return !!(attrs.header || attrs.list || attrs.blockquote || attrs["code-block"] || attrs.align || attrs.indent);
@@ -3939,7 +4014,7 @@ function collectTableLines2(lines, startIndex) {
3939
4014
  }
3940
4015
  return result;
3941
4016
  }
3942
- function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = false, registry) {
4017
+ function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = false, registry, softBreakStyle = "spaces") {
3943
4018
  const rows = /* @__PURE__ */ new Map();
3944
4019
  for (const line of tableLines) {
3945
4020
  const attrs = line.attributes;
@@ -3976,7 +4051,9 @@ function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = fa
3976
4051
  const mdLines = [];
3977
4052
  if (headerRows.length > 0) {
3978
4053
  for (const [, row] of headerRows) {
3979
- mdLines.push(renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry));
4054
+ mdLines.push(
4055
+ renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4056
+ );
3980
4057
  }
3981
4058
  mdLines.push(renderMdSeparator(maxCol, colAligns));
3982
4059
  } else {
@@ -3984,15 +4061,19 @@ function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = fa
3984
4061
  for (let col = 0; col <= maxCol; col++) {
3985
4062
  emptyRow.set(col, { ops: [] });
3986
4063
  }
3987
- mdLines.push(renderMdRow(emptyRow, maxCol, embedRenderers, useLatexDelimiters, registry));
4064
+ mdLines.push(
4065
+ renderMdRow(emptyRow, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4066
+ );
3988
4067
  mdLines.push(renderMdSeparator(maxCol, colAligns));
3989
4068
  }
3990
4069
  for (const [, row] of bodyRows) {
3991
- mdLines.push(renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry));
4070
+ mdLines.push(
4071
+ renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4072
+ );
3992
4073
  }
3993
4074
  return mdLines.join("\n");
3994
4075
  }
3995
- function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false, registry) {
4076
+ function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false, registry, softBreakStyle = "spaces") {
3996
4077
  const parts = [];
3997
4078
  for (let col = 0; col <= maxCol; col++) {
3998
4079
  const cell = cells.get(col);
@@ -4003,7 +4084,10 @@ function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false,
4003
4084
  useLatexDelimiters,
4004
4085
  void 0,
4005
4086
  false,
4006
- registry
4087
+ registry,
4088
+ softBreakStyle,
4089
+ true
4090
+ // inTableCell — softBreak must use <br>, never " \n"
4007
4091
  ) : "";
4008
4092
  parts.push(content.replace(/\|/g, "\\|"));
4009
4093
  }
@@ -4032,7 +4116,7 @@ function getCodeBlockLanguage2(attributes) {
4032
4116
  }
4033
4117
  return void 0;
4034
4118
  }
4035
- function renderLineContent2(ops, embedRenderers, inCodeBlock, useLatexDelimiters = false, blockHandlers, prettyHtml = false, registry) {
4119
+ function renderLineContent2(ops, embedRenderers, inCodeBlock, useLatexDelimiters = false, blockHandlers, prettyHtml = false, registry, softBreakStyle = "spaces", inTableCell = false) {
4036
4120
  let result = "";
4037
4121
  for (const op of ops) {
4038
4122
  const attrs = op.attributes;
@@ -4052,7 +4136,9 @@ function renderLineContent2(ops, embedRenderers, inCodeBlock, useLatexDelimiters
4052
4136
  useLatexDelimiters,
4053
4137
  blockHandlers,
4054
4138
  prettyHtml,
4055
- registry
4139
+ registry,
4140
+ softBreakStyle,
4141
+ inTableCell
4056
4142
  );
4057
4143
  }
4058
4144
  }
@@ -4086,13 +4172,17 @@ function renderInlineText2(text, attributes) {
4086
4172
  }
4087
4173
  return result;
4088
4174
  }
4089
- function renderEmbed2(embed, attributes, customRenderers, useLatexDelimiters = false, blockHandlers, prettyHtml = false, registry) {
4175
+ function renderEmbed2(embed, attributes, customRenderers, useLatexDelimiters = false, blockHandlers, prettyHtml = false, registry, softBreakStyle = "spaces", inTableCell = false) {
4090
4176
  const entries = Object.entries(embed);
4091
4177
  if (entries.length === 0) return "";
4092
4178
  const firstEntry = entries[0];
4093
4179
  if (!firstEntry) return "";
4094
4180
  const embedType = firstEntry[0];
4095
4181
  const embedValue = firstEntry[1];
4182
+ if (embedType === "softBreak") {
4183
+ if (inTableCell) return "<br>";
4184
+ return softBreakStyle === "html" ? "<br>" : " \n";
4185
+ }
4096
4186
  if (embedType === "block" && blockHandlers) {
4097
4187
  const blockData = embedValue;
4098
4188
  if (blockData && typeof blockData.type === "string") {
@@ -4243,6 +4333,8 @@ var remarkGfm = null;
4243
4333
  var remarkMath = null;
4244
4334
  var unified = null;
4245
4335
  function isRemarkAvailable() {
4336
+ if (unified && remarkParse) return true;
4337
+ if (typeof require === "undefined") return false;
4246
4338
  try {
4247
4339
  require.resolve("unified");
4248
4340
  require.resolve("remark-parse");
@@ -4251,8 +4343,8 @@ function isRemarkAvailable() {
4251
4343
  return false;
4252
4344
  }
4253
4345
  }
4254
- async function loadRemark() {
4255
- if (unified) return;
4346
+ async function preloadRemark() {
4347
+ if (unified && remarkParse && remarkGfm) return true;
4256
4348
  try {
4257
4349
  const [unifiedMod, remarkParseMod, remarkGfmMod] = await Promise.all([
4258
4350
  import("unified"),
@@ -4263,15 +4355,16 @@ async function loadRemark() {
4263
4355
  remarkParse = remarkParseMod.default;
4264
4356
  remarkGfm = remarkGfmMod.default;
4265
4357
  } catch {
4266
- throw new Error(
4267
- "remark is not installed. Install with: pnpm add unified remark-parse remark-gfm"
4268
- );
4358
+ return false;
4269
4359
  }
4270
- try {
4271
- const remarkMathMod = await import("remark-math");
4272
- remarkMath = remarkMathMod.default;
4273
- } catch {
4360
+ if (!remarkMath) {
4361
+ try {
4362
+ const remarkMathMod = await import("remark-math");
4363
+ remarkMath = remarkMathMod.default;
4364
+ } catch {
4365
+ }
4274
4366
  }
4367
+ return true;
4275
4368
  }
4276
4369
  function preprocessMarkdown(markdown, mathBlock) {
4277
4370
  markdown = markdown.replace(/\\\((.+?)\\\)/g, (_match, content) => `$${content}$`);
@@ -4295,9 +4388,11 @@ async function markdownToDelta(markdown, options = {}) {
4295
4388
  nodeHandlers = {}
4296
4389
  } = options;
4297
4390
  markdown = preprocessMarkdown(markdown, mathBlock);
4298
- await loadRemark();
4299
- if (!unified || !remarkParse) {
4300
- throw new Error("Failed to load remark");
4391
+ const loaded = await preloadRemark();
4392
+ if (!loaded || !unified || !remarkParse) {
4393
+ throw new Error(
4394
+ "remark is not installed. Install with: pnpm add unified remark-parse remark-gfm"
4395
+ );
4301
4396
  }
4302
4397
  let processor = unified().use(remarkParse);
4303
4398
  if (gfm && remarkGfm) {
@@ -4326,6 +4421,11 @@ function markdownToDeltaSync(markdown, options = {}) {
4326
4421
  } = options;
4327
4422
  markdown = preprocessMarkdown(markdown, mathBlock);
4328
4423
  if (!unified || !remarkParse) {
4424
+ if (typeof require === "undefined") {
4425
+ throw new Error(
4426
+ "markdownToDeltaSync requires remark to be preloaded in this environment. `require()` is not available (likely browser ESM). Call `await preloadRemark()` once on application startup before using the sync API, or use the async `markdownToDelta()` instead."
4427
+ );
4428
+ }
4329
4429
  try {
4330
4430
  const unifiedMod = require("unified");
4331
4431
  const remarkParseMod = require("remark-parse");
@@ -4571,7 +4671,7 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4571
4671
  footnoteDefinitions.set(node.identifier ?? "", node);
4572
4672
  break;
4573
4673
  case "break":
4574
- context.pushNewline();
4674
+ context.pushEmbed({ softBreak: true });
4575
4675
  break;
4576
4676
  case "html": {
4577
4677
  const htmlContent = node.value ?? "";
@@ -4877,8 +4977,8 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4877
4977
  context.pushNewline();
4878
4978
  return;
4879
4979
  }
4880
- if (/^<br\s*\/?>$/i.test(html)) {
4881
- context.pushNewline();
4980
+ if (/^<br\b[^>]*\/?>$/i.test(html)) {
4981
+ context.pushEmbed({ softBreak: true });
4882
4982
  return;
4883
4983
  }
4884
4984
  }
@@ -4914,6 +5014,54 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4914
5014
  }
4915
5015
  return delta;
4916
5016
  }
5017
+
5018
+ // src/conversion/markdown/table-region.ts
5019
+ var import_delta11 = require("@scrider/delta");
5020
+ function isTableNewlineOp(op) {
5021
+ if (!op || !(0, import_delta11.isInsert)(op) || !(0, import_delta11.isTextInsert)(op)) return false;
5022
+ if (!op.insert.includes("\n")) return false;
5023
+ return !!op.attributes && "table-row" in op.attributes;
5024
+ }
5025
+ function extractTableRegion(ops, hintOpIdx) {
5026
+ if (hintOpIdx < 0 || hintOpIdx >= ops.length) return null;
5027
+ let probeIdx = -1;
5028
+ for (let i = hintOpIdx; i < ops.length; i++) {
5029
+ const op = ops[i];
5030
+ if (!op || !(0, import_delta11.isInsert)(op)) continue;
5031
+ if ((0, import_delta11.isTextInsert)(op) && op.insert.includes("\n")) {
5032
+ probeIdx = i;
5033
+ break;
5034
+ }
5035
+ }
5036
+ if (probeIdx < 0) return null;
5037
+ if (!isTableNewlineOp(ops[probeIdx])) return null;
5038
+ let endOpIdx = probeIdx;
5039
+ for (let i = probeIdx + 1; i < ops.length; i++) {
5040
+ const op = ops[i];
5041
+ if (!op || !(0, import_delta11.isInsert)(op)) break;
5042
+ if ((0, import_delta11.isTextInsert)(op) && op.insert.includes("\n")) {
5043
+ if (isTableNewlineOp(op)) {
5044
+ endOpIdx = i;
5045
+ } else {
5046
+ break;
5047
+ }
5048
+ }
5049
+ }
5050
+ let startOpIdx = 0;
5051
+ for (let i = probeIdx - 1; i >= 0; i--) {
5052
+ const op = ops[i];
5053
+ if (!op || !(0, import_delta11.isInsert)(op)) {
5054
+ startOpIdx = i + 1;
5055
+ break;
5056
+ }
5057
+ if ((0, import_delta11.isTextInsert)(op) && op.insert.includes("\n") && !isTableNewlineOp(op)) {
5058
+ startOpIdx = i + 1;
5059
+ break;
5060
+ }
5061
+ }
5062
+ const regionOps = ops.slice(startOpIdx, endOpIdx + 1);
5063
+ return { startOpIdx, endOpIdx, ops: regionOps };
5064
+ }
4917
5065
  // Annotate the CommonJS export names for ESM import in node:
4918
5066
  0 && (module.exports = {
4919
5067
  ALERT_TYPES,
@@ -4948,6 +5096,7 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4948
5096
  dividerFormat,
4949
5097
  escapeHtml,
4950
5098
  extractBoxOpAttributes,
5099
+ extractTableRegion,
4951
5100
  fontFormat,
4952
5101
  footnoteRefFormat,
4953
5102
  footnotesBlockHandler,
@@ -4962,6 +5111,7 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4962
5111
  isAdapterAvailable,
4963
5112
  isElement,
4964
5113
  isRemarkAvailable,
5114
+ isTableNewlineOp,
4965
5115
  isTextNode,
4966
5116
  isValidColor,
4967
5117
  isValidHexColor,
@@ -4974,10 +5124,12 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4974
5124
  markdownToDeltaSync,
4975
5125
  nodeAdapter,
4976
5126
  normalizeDelta,
5127
+ preloadRemark,
4977
5128
  sanitizeDelta,
4978
5129
  sizeFormat,
4979
5130
  slugify,
4980
5131
  slugifyWithDedup,
5132
+ softBreakFormat,
4981
5133
  strikeFormat,
4982
5134
  subscriptFormat,
4983
5135
  superscriptFormat,